﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QString>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_btnLookFile_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, "选择图片", "", "*.jpg *.bmp *.png");
    QFile file(fileName);
    if (!file.exists()) {
        qDebug() << "文件不存在：" << fileName;
        return;
    }

    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "无法打开文件：" << file.errorString();
        return;
    }

    QByteArray data = file.readAll();
    imageBuffer.assign(data.constData(), data.constData() + data.size());
    file.close();

    ui->imagePath->setText(fileName);
    imagePath = fileName.toStdString();
    QPixmap pixmap(fileName);
    ui->lblDetectImage->setPixmap(pixmap.scaled(ui->lblDetectImage->size(), Qt::KeepAspectRatio));
}

void MainWindow::on_btnClassNames_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("选择标签"), "", QStringLiteral("*.names"));
    ui->ledtNames->setText(fileName);
    classNamesPath = ui->ledtNames->text().toStdString();
    classNames = util::loadNames(classNamesPath);
}

void MainWindow::on_btnModel_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("选择模型"), "", QStringLiteral("*.onnx"));
    ui->ledtModel->setText(fileName);
    modelPath = ui->ledtModel->text().toStdString();
}

void MainWindow::on_btnDetect_clicked()
{
    // 1. 加载图像
    cv::Mat image = cv::imdecode(imageBuffer, cv::IMREAD_COLOR);
    if(image.empty()) {
        qDebug() << "无法解码图片";
    }

    cv::Mat result_image = exeDetect(image, "image");
    QImage qimg(result_image.data, result_image.cols, result_image.rows, result_image.step, QImage::Format_RGB888);//将 OpenCV Mat 转换为 QImage 并显示
    QPixmap pixmap = QPixmap::fromImage(qimg.rgbSwapped());
    ui->detectImage->setPixmap(pixmap.scaled(ui->detectImage->size(), Qt::KeepAspectRatio));
}

void MainWindow::on_btnDnn_clicked()
{
    // 1. 加载图像
    cv::Mat frame = cv::imdecode(imageBuffer, cv::IMREAD_COLOR);
    if(frame.empty()) {
        qDebug() << "无法解码图片";
    }

    bool runOnGPU = false;
    DnnDetector dnnDetector(modelPath, cv::Size(640, 640), classNames, runOnGPU);

    // 2. 设置你的输入图片
    std::vector<Detection> output = dnnDetector.detect(frame);

    int detections = output.size();
    std::cout << "Number of detections:" << detections << std::endl;

    for (int i = 0; i < detections; ++i)
    {
        Detection detection = output[i];

        cv::Rect box = detection.box;
        cv::Scalar color = detection.color;

        // Detection box
        cv::rectangle(frame, box, color, 4);

        // Detection box text
        std::string classString = detection.className + ' ' + std::to_string(detection.confidence).substr(0, 4);
        cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
        cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);

        cv::rectangle(frame, textBox, color, cv::FILLED);
        cv::putText(frame, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
    }

    std::string output_path = "result_" + imagePath;
    cv::imwrite(output_path, frame);
    qDebug() << "Detection completed. Results saved to detection_result.jpg";

    // 显示结果
    cv::imshow("Detection Result", frame);

    QImage qimg(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888);//将 OpenCV Mat 转换为 QImage 并显示
    QPixmap pixmap = QPixmap::fromImage(qimg.rgbSwapped());
    ui->detectImage->setPixmap(pixmap.scaled(ui->detectImage->size(), Qt::KeepAspectRatio));
}

// 创建目录（如果不存在）
bool MainWindow::createDirectoryIfNotExists(const std::string& dirPath) {
    if (!fs::exists(dirPath)) {
        try {
            fs::create_directories(dirPath);
            std::cout << "目录已创建: " << dirPath << std::endl;
            return true;
        } catch (const fs::filesystem_error& e) {
            std::cerr << "创建目录失败: " << e.what() << std::endl;
            return false;
        }
    }
    std::cout << "目录已存在: " << dirPath << std::endl;
    return true;
}

void MainWindow::on_action_camera_triggered(bool checked)
{
    if(capture.isOpened()){
        capture.release();
        ui->lblDetectImage->setPixmap(QPixmap());
        ui->detectImage->setPixmap(QPixmap());
        delete camera_timer;
        camera_timer = nullptr;
    }
    else{
        capture.open(0);
        if(!capture.isOpened()){
            capture.open(1);
        }
        if(!capture.isOpened()){
            qDebug() << "ERROR: Can't initialize camera capture";
        }
        else{
            camera_timer = new QTimer(this);
            connect(camera_timer, &QTimer::timeout, this, [=](){
                camera_timer->stop();
                //捕获图像帧
                capture>>frame;
                //将视频显示到screen上
                QImage image = QImage((const uchar*)frame.data, frame.cols, frame.rows, QImage::Format_RGB888).rgbSwapped();
                ui->lblDetectImage->setPixmap(QPixmap::fromImage(image));
                if(!classNames.empty() && !modelPath.empty()){
                    cv::Mat result_image = exeDetect(frame, "camera");
                    QImage detectImage = QImage((const uchar*)result_image.data, result_image.cols, result_image.rows, QImage::Format_RGB888).rgbSwapped();
                    ui->detectImage->setPixmap(QPixmap::fromImage(detectImage));
                }
                camera_timer->start(25);
            });
            camera_timer->start(25);
        }
    }
}

cv::Mat MainWindow::exeDetect(cv::Mat image, QString source){
    // 初始化检测器
    auto start_load = std::chrono::high_resolution_clock::now();
    OnnxDetector detector(modelPath, classNames, 0.5, 0.45);
    auto end_load = std::chrono::high_resolution_clock::now();
    auto load_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_load - start_load).count();
    std::cout << "模型加载时间: " << load_time << " ms" << std::endl;

    // 记录原始图像尺寸
    int original_width = image.cols;
    int original_height = image.rows;
    std::cout << "图像尺寸: " << original_width << " x " << original_height << std::endl;

    // 执行目标检测
    auto start_detect = std::chrono::high_resolution_clock::now();
    auto detections = detector.detect(image);
    auto end_detect = std::chrono::high_resolution_clock::now();
    auto detect_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_detect - start_detect).count();

    // 输出检测结果
    std::cout << "\n检测到 " << detections.size() << " 个目标:\n";
    for (const auto& detection : detections) {
        std::cout << detection.label << " ("
                  << std::fixed << std::setprecision(2) << detection.confidence * 100 << "%) "
                  << "位置: [" << static_cast<int>(detection.bbox.x) << ", "
                  << static_cast<int>(detection.bbox.y) << ", "
                  << static_cast<int>(detection.bbox.width) << ", "
                  << static_cast<int>(detection.bbox.height) << "]\n";
    }

    // 保存检测结果到文件
    detector.save_detections_to_file(detections, detections_file);
    std::cout << "检测结果已保存至: " << detections_file << std::endl;

    // 绘制并保存结果图像
    cv::Mat result_image = detector.draw_detections(image, detections);

    //提取目录和文件名
    std::string dirPath;
    std::string filename;
    if(source == "image"){
        fs::path inputFilePath(imagePath);
        dirPath = inputFilePath.parent_path().string();     // 输入文件所在目录
        filename = inputFilePath.filename().string();       // 原始文件名（含扩展名）
    }
    else{
        QDir currentDir(QDir::currentPath());
        QDir baseDir(currentDir);
        //进入上级目录
        if (!baseDir.cdUp()) {
            qDebug() << "无法进入上级目录，请检查路径有效性。";
            return image;
        }
        dirPath = baseDir.filePath("model").toStdString();
        filename = "camera.jpg";
    }

    std::string targetDir = dirPath + "/dstImage";                  //构造目标路径
    std::string outputPath = targetDir + "/" + filename;

    // 判断并创建目录
    if (!createDirectoryIfNotExists(targetDir)) {
        return image; // 创建失败则退出
    }
    cv::imwrite(outputPath, result_image);
    std::cout << "结果图像已保存至: " << outputPath << std::endl;

    // 显示性能指标
    auto total_time = load_time + detect_time;
    std::cout << "\n性能指标:\n";
    std::cout << "模型加载时间: " << load_time << " ms\n";
    std::cout << "检测时间: " << detect_time << " ms\n";
    std::cout << "总时间: " << total_time << " ms\n";
    std::cout << "FPS: " << 1000.0 / detect_time << "\n";

    return result_image;
};

void MainWindow::on_action_image_triggered(bool checked)
{
    LoadingDialog::Loading();
    LoadingDialog::ProcessEvent();
}

